import SysMenuModel from "../../dao/model/system/SysMenuModel";
import SysUserModel from "../../dao/model/system/SysUserModel";
import SysMenuEntity, { IMenuModel } from "../../entities/system/SysMenuEntity";
import { IUserModel } from "../../entities/system/SysUserEntity";
import { IPageResponse } from "../../types/CommonType";
import { ValidationError } from "../../utils/errors";
import { getTreeStructure, pick } from "../../utils/tools";
import { buildMenus } from "./utils/menuTool";

export class SysMenuService {
  /**
   * 添加数据
   */
  public static async add(data: SysMenuEntity): Promise<true> {
    // 1. 转换类型
    data = SysMenuEntity.transform(data);
    // 2. 数据验证
    const errors = await data.validateThis();
    if (errors.length > 0) {
      throw new ValidationError(errors[0]);
    }

    await SysMenuModel.create<IMenuModel>(data);
    return true;
  }

  /**
   * 分页获取数据
   */
  public static async findByPage(current: number, size: number, where = {}): Promise<IPageResponse> {
    let data = await SysMenuModel.findAndCountAll<IMenuModel>({
      offset: size * (current - 1),
      limit: size,
      where,
    });

    const result: IPageResponse = {
      total: data.count,
      list: data.rows.map((item) => item.dataValues),
    };

    return result;
  }

  /**
   * 通过id获取数据
   */
  public static async findById(id: string) {
    return SysMenuModel.findByPk<IMenuModel>(id);
  }

  /**
   * 修改数据
   */
  public static async update(data: any) {
    return SysMenuModel.update<IMenuModel>(data, {
      where: {
        id: data.id,
      },
    });
  }

  /**
   * 删除数据
   */
  public static async delete(id: string) {
    return SysMenuModel.destroy({
      where: {
        id,
      },
    });
  }

  /**
   * 获取前端路由菜单结构
   */
  public static async findByFrontEndRouter(userInfo: any) {
    const user = await SysUserModel.findByPk<IUserModel>(userInfo.id);
    if (!user) {
      throw new ValidationError("获取当前账号角色信息失败");
    }

    let menuList: IMenuModel[] | SysMenuEntity[] = [];
    const [role] = await user.getRole();

    // 1. 根据条件获取菜单
    async function getMenuByCondition() {
      // 如果是超级管理员则返回所有菜单
      if (role.dataValues.roleKey === "admin") {
        menuList = await SysMenuModel.scope({}).findAll<IMenuModel>({
          order: [["orderNum", "ASC"]],
        });
      } else {
        // 否则获取当前角色的菜单
        menuList = await role.getMenu({
          order: [["orderNum", "ASC"]],
          scope: false,
        });
      }
      menuList = menuList.map((item) => item.dataValues);
    }
    await getMenuByCondition();

    /**
     * 补全菜单
     */
    async function compleMenu() {
      const menuIds = menuList.map((item: any) => item.id);

      // 1. 记录要补充的菜单
      const menus: SysMenuEntity[] = [];

      // 2. 判断现有的菜单id中是否有其父菜单的id，没有则补充
      for (const item of menuList as SysMenuEntity[]) {
        if (item.parentId !== 0 && !menuIds.includes(item.parentId)) {
          const menu = await SysMenuModel.findByPk<IMenuModel>(item.parentId);

          menu && menus.push(menu.dataValues);
        }
      }

      if (menus.length > 0) {
        menuList = [...menuList, ...menus] as SysMenuEntity[];

        // 对结果进行排序
        menuList.sort((a: SysMenuEntity, b: SysMenuEntity) => +a.orderNum - +b.orderNum);
      }
    }
    await compleMenu();

    return buildMenus(menuList);
  }

  public static async findByTreeSelect() {
    const list = await SysMenuModel.scope({}).findAll<IMenuModel>({
      order: [["orderNum", "ASC"]],
    });
    const data = list.map((item) => pick(item.dataValues, ["menuName", "id", "parentId"]));
    return getTreeStructure<(typeof data)[0]>(data, "id", "parentId");
  }

  /**
   * 获取全部数据
   */
  public static async findByList() {
    return await SysMenuModel.scope({}).findAll<IMenuModel>({
      order: [["orderNum", "ASC"]],
    });
  }
}
